package com.screwdriver.jso.processor.utils;

import com.screwdriver.jso.client.annotation.JSOInterface;
import com.sun.mirror.declaration.InterfaceDeclaration;
import com.sun.mirror.declaration.MethodDeclaration;
import com.sun.mirror.type.InterfaceType;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * Created by IntelliJ IDEA. User: jan kowalski Date: 08.08.11 Time: 23:34 To
 * change this template use File | Settings | File Templates.
 */
@SuppressWarnings("deprecation")
public class TypeUtil {

    private TypeUtil() {
    }

    public static boolean checkIfInterfaceDeclaresMethod(InterfaceDeclaration id, MethodDeclaration md) {
        if (id == null)
            return false;
        return getInvolvedInterfaces(id).contains(md.getDeclaringType());
    }

    private static Set<InterfaceDeclaration> getInvolvedInterfaces(InterfaceDeclaration id) {
        Set<InterfaceDeclaration> result = new HashSet<InterfaceDeclaration>();
        result.add(id);
        for (InterfaceType interfaceType : id.getSuperinterfaces()) {
            result.addAll(getInvolvedInterfaces(interfaceType.getDeclaration()));
        }
        return result;
    }

    public static InterfaceDeclaration inferSuperType(InterfaceDeclaration td) {
        Set<InterfaceDeclaration> implementingJSOs = getSuperJSOInterfaces(td);
        implementingJSOs.remove(td);
        if (implementingJSOs.size() > 1) {
            throw new RuntimeException(String.format("Ambiguous super JSO type: %s",
                    Arrays.toString(implementingJSOs.toArray(new String[implementingJSOs.size()]))));
        } else if (implementingJSOs.size() == 1) {
            return implementingJSOs.iterator().next();
        }
        return null;
    }


    public static Set<InterfaceDeclaration> getSuperJSOInterfaces(InterfaceDeclaration td) {
        Set<InterfaceDeclaration> implementingJSOs = new HashSet<InterfaceDeclaration>();
        Collection<InterfaceType> superinterfaces = td.getSuperinterfaces();
        if (superinterfaces.size() == 0) {
            if (td.getAnnotation(JSOInterface.class) != null) {
                implementingJSOs.add(td);
            }
        } else {
            for (InterfaceType it : superinterfaces) {
                implementingJSOs.addAll(getSuperJSOInterfaces(it.getDeclaration()));
            }
        }
        return implementingJSOs;
    }

    public static boolean isMethodImplementedByOtherJso(MethodDeclaration md, InterfaceDeclaration rootType) {
        for (InterfaceType it : rootType.getSuperinterfaces()) {
            if (it.getDeclaration().getAnnotation(JSOInterface.class) != null) {
                if (checkIfInterfaceDeclaresMethod(it.getDeclaration(), md)) {
                    return true;
                }
            }
        }
        return false;
    }
}
